import requests
import re
import binascii
from Crypto.Cipher import DES
from Crypto.Util.Padding import pad


def encrypt_pwd(pwd, key):
    mode = DES.MODE_ECB
    cryptos = DES.new(key, mode)
    cipher_text = cryptos.encrypt(pad(str.encode(pwd), 16, 'pkcs7'))
    return cipher_text


def encrypt(pd, key):
    key = binascii.a2b_base64(key.encode('utf-8'))
    pd_bytes = encrypt_pwd(pd, key)
    pd_base64 = binascii.b2a_base64(pd_bytes, newline=False).decode('utf-8')
    return pd_base64


class Clock:
    def __init__(self, pname: str, uname: str, pwd: str):
        self.session = requests.session()
        self.session.headers = {
            'Connection': 'keep-alive',
            'Accept': '*/*',
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36 Edg/114.0.1823.58',
            'Accept-Encoding': 'gzip, deflate',
            'Accept-Language': 'zh-CN,zh;q=0.9',
        }
        self.xh = uname
        self.person_name = pname
        if not self.sso_login(uname, pwd):
            self.session = None
            print("Login failed")

    def sso_login(self, uname: str, pwd: str) -> bool:
        url = "http://xgxt.zstu.edu.cn/swms/a"
        sso_url = "https://sso.zstu.edu.cn/login"
        req = self.session.get(url)
        req = self.session.get(req.url).text
        croypto = re.search(r'<p id="login-croypto">(.*?)</p>', req).group(1)
        execution = re.search(r'<p id="login-page-flowkey">(.*?)</p>', req).group(1)
        data = {
            'username': uname,
            'type': 'UsernamePassword',
            '_eventId': 'submit',
            'geolocation': '',
            'execution': execution,
            'captcha_code': '',
            'croypto': croypto,
            'password': encrypt(pwd, croypto)
        }
        self.session.cookies.update({'isPortal': 'false'})
        resp = self.session.post(sso_url, data=data)
        if resp.status_code == 401:
            return False
        self.session.get(resp.url)
        return True

    def check(self) -> bool:
        return self.session != None

    def _get_wid(self):
        self.session.get("http://xgxt.zstu.edu.cn/swms/a/sysApp?appId=533fbc231b0d4d1fb106187e6d14de9e")
        req = self.session.get("http://xgxt.zstu.edu.cn/swms/a/zxqd/qdjg/qdList").text
        res = re.findall('<input[^>]*name="chk"[^>]*value="([^"]+)"[^>]*>', req)[0]
        return res

    def clock(self):
        assert self.check(), "登陆失败"
        jgid = self._get_wid()
        req = self.session.post("http://xgxt.zstu.edu.cn/swms/a/zxqd/qdjg/checkDz", {
            'qdjd': '120.37052', 'qdwd': '30.32235',
            'rwid': 'FE22C5B453974DF7E0500C0A5F032F17'})
        qdjl = re.search('"qdjl":(\d+\.\d+)', req.text).group(1)
        res = self.session.post(
            f"http://xgxt.zstu.edu.cn/swms/a/zxqd/qdjg/xsqd?qdjd={120.36611}&qdwd={30.32222}&qddz={'浙江省杭州市钱塘区学林街164号'}&bz=&qdjl={qdjl}",
            {
                'xsid': self.xh, 'rwid': 'FE22C5B453974DF7E0500C0A5F032F17', 'jgid': jgid}, allow_redirects=False)
        if res.status_code == 303:
            return True
        return False

    def clock_info(self):
        if not self.check(): return "登陆失败"
        jgid = self._get_wid()
        if jgid is None: return "今日打卡任务尚未发布"
        res = self.session.get(f"http://xgxt.zstu.edu.cn/swms/a/zxqd/qdjg/qdjgForm?wid={jgid}&doWhat=view").text
        sfqd = re.findall('<input[^>]*name="sfqd"[^>]*value="([^"]+)"[^>]*>', res)[0]
        if sfqd == '否': return "今天还没签到"
        qdsj = re.findall('<input[^>]*name="qdsj"[^>]*value="([^"]+)"[^>]*>', res)[0]
        qddz = re.findall('<input[^>]*name="qddz"[^>]*value="([^"]+)"[^>]*>', res)[0]
        return f"用户：{self.person_name}\t签到时间：{qdsj.strip()}\t签到地址：{qddz.strip()}"

t = Clock("lh", "202130504106", "Lh13666895038")
if t.clock():
    print("打卡成功")
else:
    print("打卡失败")
print(t.clock_info())